"""
无依赖的纯净工具箱

* 一些数据类型转换工具
* 测试api接口, 使用requests实现http请求.
* 测试函数运行效率的方法 test_f_speed()

"""
from copy import deepcopy
import os
import json
import requests
from bdtime import tt


def bytes_to_json(bytes_str: bytes):
    ret = bytes_str.decode('utf-8')
    json.loads(ret)
    return ret


def json_to_dict(data)->dict:
    data = json.loads(data)
    return data


bytes_to_dict = json_to_dict


def mytest_api(url, method=requests.get, *args, **kwargs):
    try:
        r = method(url,  *args, **kwargs)

        print('HTTP_Status:', r)

        data = json_to_dict(r.content)

        if(isinstance(data, list)):
            for dc in data:     print(dc)

        else:
            print(data)

        print()

    except Exception as e:
        print('traceback--> ', e)


test_api = mytest_api



def show_ls(ls):
    assert isinstance(ls, list), 'input must be a list!'
    for d in ls:    print(d)


def get_headers():
    headers = {'Content-Type': 'application/json'}
    return headers


def get_GET_ret(url, headers=None):
    headers = headers if headers else get_headers()
    try:
        r = requests.get(url, headers=headers)
        print('HTTP_Status:', r)

        data = json_to_dict(r.content)
    except Exception as e:
        print('traceback--> ', e)
        return None

    return data


def test_post(url, data):
    data = data_to_json(data)
    url = add_slash_to_url(url)
    headers = get_headers()

    test_api(url, requests.post, data=data, headers=headers)


def get_POST_ret(url, data)->dict:
    data = data_to_json(data)
    url = add_slash_to_url(url)
    headers = get_headers()

    r = requests.post(url, data=data, headers=headers)
    # test_api(url, requests.post, data=data, headers=headers)
    print('HTTP_Status:', r)

    data = json_to_dict(r.content)

    if (isinstance(data, list)):
        for dc in data:     print(dc)

    else:
        print(data)

    ret = data
    return ret



def data_to_json(data):
    if isinstance(data, (list, dict)):
        data = json.dumps(data)

    return data


def add_slash_to_url(url):
    if not url.endswith('/'):
        url += '/'
    return url


def test_put(url, data):
    data = data_to_json(data)
    url = add_slash_to_url(url)
    headers = get_headers()

    test_api(url, requests.put, data=data, headers=headers)


def test_delete(url):
    test_api(url, requests.delete)


def conv_to_same_format(v1, v2):
    # v1 转换为 v2 的数据类型

    v2_type = type(v2)
    if isinstance(v1, v2_type):
        return v1
    else:
        if type(v1) in (list, dict):
            if v2_type not in (list, dict):
                v1 = v1[0]      # v1为list, 而v2不是时, 尝试将 v1: value 转换为 v1[0].

        if(not v1):
            # v1为空的时候, 直接用v2覆盖, 避免类型转换错误.
            v1 = v2
        try:
            ret = v2_type(v1)
        except Exception as e:
            # raise e
            raise ValueError(f'conv type failed! v1: {v1}, v2: {v2}')
        return ret


def get_value_from_request_dict(key, dc):
    value = dc.get(key)

    # 若为list, 则返回基本类型
    if isinstance(value, list):
        value = value[0]

    return value


def eval_plus(xx, conv_type=int):
    # force convert the [input type] to [numeric type]
    if isinstance(xx, list):
        xx = xx[0]

    try:
        # str 优先 eval.
        if isinstance(xx, str):
            return eval(xx)
    except:
        try:
            xx = conv_type(xx)
        except:
            print('转换为指定类型失败! 尝试其它类型中...')
            try:
                xx = int(xx)
            except:
                try:
                    xx = float(xx)
                except:
                    raise TypeError('请确认输入可以转换为数字类型!')
    return xx


def replace_dict_empty_values_as_same_format(dc: dict, default_dc: dict) -> dict:
    """
    将dc中空的key-values转换为默认字典default_dc中的数据, 数值转换时将转为同种数据类型.

    :param dc: 原字典
    :param default_dc: 保存替换数据的字典
    :return: 替换完成后的字典
    """
    dc_new = deepcopy(dc)       # raise bug: This QueryDict instance is immutable

    if not dc_new:
        return default_dc

    for k, v in default_dc.items():
        new_v = dc.get(k)
        print(k, v, new_v, type(v) == type(new_v))

        dc_new[k] = conv_to_same_format(new_v, v) if new_v else v  # 如果 dc_v 为空, 则转换为defalt_dc.v的同种数据类型后再保存.

    return dc_new


def random_choose_from_dict(dc: dict, nums=1)->dict:
    # 从大dict中随机抽取nums个数, 返回小dict格式.
    ks = list(dc.keys())[:nums]
    vs = [dc.get(k) for k in ks]

    ret = dict(zip(ks, vs))
    return ret


def merge_ordered_dict(dc1, dc2):
    # 两个字典合并
    merge_ordereddict = dc1.copy()
    merge_ordereddict.update(dc2)
    return merge_ordereddict


def add_status_and_msg(dc_ls, status=200, msg=None):
    if status != 200 and msg == None:
        msg = '请求数据失败!'
    else:
        msg = "OK"

    ret = {
        'status': status,
        'msg': msg,
        'result': None,
    }

    dc = {'result': dc_ls}
    ret.update(dc)

    return ret


def mytest_f_speed(f, run_times=20):
    '''
    测试函数运行效率

    f1 = lambda: SingleChoiceQuestions.objects.aggregate(Max('id'))
    f2 = lambda: SingleChoiceQuestions.objects.all().latest('id').id
    test_f_speed(f1, 1000)

    :param f: lambda, 函数表达式
    :param run_times: 运行次数
    :return:
    '''

    print('最大测试次数: ', run_times)

    tt.__init__()
    for i in range(run_times):
        f()
    print(f'运行 {run_times} 次的时间为: {tt.now(1)}秒, 平均速度: {round(tt.now(1)/run_times, 2)} 秒/次')

test_f_speed = mytest_f_speed
# from rest_framework.response import Response
#
#
# def _cnki_response(status, msg):
#     _Http_dc = {
#         'status': status,
#         'msg': msg,
#     }
#     ret = Response(_Http_dc)
#     return ret
#
# class CNKIResponse:
#
#     def ret_404(self, msg="错误"):
#         ret = self.ret(404, msg)
#         return ret
#
#     def ret_200(self, msg="OK"):
#         ret = self.ret(200, msg)
#         return ret
#
#     def ret(self, status, msg):
#         return _cnki_response(status, msg)
#
# cnki_response = CNKIResponse()
# # cnki_response.ret_200()

def phone_number_classification(phone_number):
    phone_class = '未知分类'

    # 获取用户电话号码
    # phone_number = int(input('请输入电话号码\n'))

    # 转换为列表
    b = (int(phone_number / 100000000))
    c = [b]

    # 列入三大运营商的号段
    cmcc = [139, 138, 137, 136, 135, 134, 147, 150, 151, 152, 157, 158, 159, 178, 182, 183, 184, 187, 188, 198]
    cu = [130, 131, 132, 155, 156, 166, 185, 186, 145, 176]
    ct = [133, 153, 177, 173, 180, 181, 189, 199]
    # 进行核对
    if set(c) & set(cmcc):
        # print(f'您的电话号码是{b}号段的，属于中国移动')
        phone_class = '移动'
    elif set(c) & set(cu):
        # print(f'您的电话号码是{b}号段的，属于中国联通')
        phone_class = '联通'
    elif set(c) & set(ct):
        # print(f'您的电话号码是{b}号段的，属于中国电信')
        phone_class = '电信'
    # else:
    #     print(f'你的电话可能属于虚拟运营商')


    return phone_class

# phone_number_classification(18510779120)
#
# # 移动 & 联通 & 电信 & 虚拟/未知
# phone_number = 18786632644
# phone_number = 16685263363
# phone_number = 18083222454
# phone_number = 17022549878
# phone_number_classification(phone_number)


# def cnki_Response(res, status=200, msg='OK'):
#     if status == 200:
#         ret = utils.cnki_response.ret_200(res)
#     elif status in (400, 404):
#         if msg == 'OK':
#             msg = f'{status} Error!'
#         ret = utils.cnki_response.ret_404(res, msg)
#     else:
#         ret = utils.cnki_response.ret(res, status, msg)
#     return Response(ret)

def df_to_ls_dc(df):
    # 将 dataframe 转换为 list_dict 的形式.
    ret_dc = df.T.to_dict()
    ret = []
    for k, v in ret_dc.items():
        ret.append(v)
    return ret
